package com.effectiv.gooruda.rest.service.api;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import com.effectiv.gooruda.rest.docs.annotation.Api;
import com.effectiv.gooruda.rest.docs.annotation.ApiBodyObject;
import com.effectiv.gooruda.rest.docs.annotation.ApiHeaders;
import com.effectiv.gooruda.rest.docs.annotation.ApiHeader;
import com.effectiv.gooruda.rest.docs.annotation.ApiMethod;
import com.effectiv.gooruda.rest.docs.annotation.ApiParam;
import com.effectiv.gooruda.rest.docs.annotation.ApiResponseObject;
import com.effectiv.gooruda.rest.docs.pojo.ApiVerb;

import com.effectiv.gooruda.rest.domain.CacheEntry;
import com.hazelcast.client.HazelcastClient;
import com.hazelcast.core.IMap;

@Slf4j
@Path("/cache")
@Api(name = "Cache API", description = "Cache API.")

public abstract class CacheService {
	
	@Autowired
	@Qualifier("client")
	private HazelcastClient client;
	
	protected IMap<String, CacheEntry> getMap(String cacheName){
		String appCacheName = "" + "." + cacheName;
		
		IMap<String, CacheEntry> map = client.getMap(appCacheName);
		log.debug("Got map = {}", map);
		
		
		return map;
	}
	
	/**
	 * Get details about a cache.
	 * @param cacheName
	 * @return
	 */
	
	
	@ApiMethod(path = "/api/cache/{cacheName}", verb = ApiVerb.GET, description = "Get details about a cache.", 
			produces = { MediaType.APPLICATION_JSON }, consumes = { MediaType.APPLICATION_JSON })
	@ApiHeaders(headers = {
			@ApiHeader(name = "signature", description = "Authentication signature."),
			@ApiHeader(name = "public-key", description = "Public key of the application.") })
	
	@Path("/{cacheName}")
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public abstract  @ApiResponseObject Response findOne(@PathParam("cacheName") 
		@ApiParam(name="cacheName", description="Cache name") String cacheName);
	
	
	/**
	 * Put an entry in the cache.
	 * @param cacheName
	 * @param key
	 * @param entry
	 */
	
	@ApiMethod(path = "/api/cache//{cacheName}/key/{key}", verb = ApiVerb.POST, description = "Put an entry in the cache.", 
			produces = { MediaType.APPLICATION_JSON }, consumes = { MediaType.APPLICATION_JSON })
	@ApiHeaders(headers = {
			@ApiHeader(name = "signature", description = "Authentication signature."),
			@ApiHeader(name = "public-key", description = "Public key of the application.") })
	
	@Path("/{cacheName}/key/{key}")
	@POST
	@Produces(MediaType.APPLICATION_JSON)
	public abstract @ApiResponseObject Response  addEntry(
			@PathParam("cacheName") @ApiParam(name="cacheName", description="Cache name")  String cacheName, 
			@PathParam("key") @ApiParam(name="key", description="Key of the entry in cache.") String key, 
			@ApiBodyObject CacheEntry entry);
	
	/**
	 * Get an entry from cache.
	 * @param cacheName
	 * @param key
	 * @return
	 */
	
	@ApiMethod(path = "/api/cache//{cacheName}/key/{key}", verb = ApiVerb.GET, description = "Get an entry from cache.", 
			produces = { MediaType.APPLICATION_JSON }, consumes = { MediaType.APPLICATION_JSON })
	@ApiHeaders(headers = {
			@ApiHeader(name = "signature", description = "Authentication signature."),
			@ApiHeader(name = "public-key", description = "Public key of the application.") })
	
	@Path("/{cacheName}/key/{key}")
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public abstract @ApiResponseObject Response getEntry(
			@PathParam("cacheName") @ApiParam(name="cacheName", description="Cache name")  String cacheName, 
			@PathParam("key") @ApiParam(name="key", description="Key of the entry in cache.") String key);
	
	
	/**
	 * Delete a cache.
	 * @param cacheName
	 * @return
	 */
	
	@ApiMethod(path = "/api/cache//{cacheName}", verb = ApiVerb.DELETE, description = "Delete a cache.", 
			produces = { MediaType.APPLICATION_JSON }, consumes = { MediaType.APPLICATION_JSON })
	@ApiHeaders(headers = {
			@ApiHeader(name = "signature", description = "Authentication signature."),
			@ApiHeader(name = "public-key", description = "Public key of the application.") })
	
	@Path("/{cacheName}")
	@DELETE
	public abstract @ApiResponseObject Response delete(
			@PathParam("cacheName") @ApiParam(name="cacheName", description="Cache name")  String cacheName);
	
	/**
	 * Clear / remove all the entries in a cache
	 * @param cacheName
	 */
	@ApiMethod(path = "/api/cache/{cacheName}/clear", verb = ApiVerb.DELETE, description = "Clear / remove all the entries in a cache.", 
			produces = { MediaType.APPLICATION_JSON }, consumes = { MediaType.APPLICATION_JSON })
	@ApiHeaders(headers = {
			@ApiHeader(name = "signature", description = "Authentication signature."),
			@ApiHeader(name = "public-key", description = "Public key of the application.") })
	
	@Path("/{cacheName}/clear")
	@DELETE
	public abstract @ApiResponseObject Response clear(
			@PathParam("cacheName") @ApiParam(name="cacheName", description="Cache name") String cacheName);
	
	/**
	 * Remove an entry from the cache.
	 * @param cacheName
	 * @param key
	 * @return
	 */
	
	@ApiMethod(path = "/api/cache/{cacheName}/key/{key}/remove", verb = ApiVerb.DELETE, description = "Remove an entry from the cache.", 
			produces = { MediaType.APPLICATION_JSON }, consumes = { MediaType.APPLICATION_JSON })
	@ApiHeaders(headers = {
			@ApiHeader(name = "signature", description = "Authentication signature."),
			@ApiHeader(name = "public-key", description = "Public key of the application.") })
	
	@Path("/{cacheName}/key/{key}/remove")
	@DELETE
	public abstract @ApiResponseObject Response removeEntry(
			@PathParam("cacheName") @ApiParam(name="cacheName", description="Cache name") String cacheName, 
			@PathParam("key") @ApiParam(name="key", description="Key of the entry in cache.") String key);
	
	/**
	 * Increment a value. The key must hold an integer value, otherwise error will be raised.
	 * @param cacheName
	 * @param key
	 * @return
	 */
	
	@ApiMethod(path = "/api/cache/{cacheName}/key/{key}/increment", verb = ApiVerb.DELETE, description = "Remove an entry from the cache.", 
			produces = { MediaType.APPLICATION_JSON }, consumes = { MediaType.APPLICATION_JSON })
	@ApiHeaders(headers = {
			@ApiHeader(name = "signature", description = "Authentication signature."),
			@ApiHeader(name = "public-key", description = "Public key of the application.") })
	
	@Path("/{cacheName}/key/{key}/increment")
	@POST
	@Produces(MediaType.APPLICATION_JSON)
	public abstract @ApiResponseObject Response increment(@PathParam("cacheName") @ApiParam(name="cacheName", description="Cache name") String cacheName, 
			@PathParam("key") @ApiParam(name="key", description="Key of the entry in cache.") String key);

	// List<Cache> listCaches();
	// List<CacheEntry> findAll(String cacheName, String selector);
}
